package value

import (
	"database/sql"
	errors2 "gitee.com/go-web-2/orm_framework/errors"
	"gitee.com/go-web-2/orm_framework/session/model"
	"reflect"
	"strings"
	"unsafe"
)

/**
说明： unsafe比reflect操作更底层，性能更好，也更危险。危险比如要求输入vals是正确，unsafe不会校验合法性
*/

type UnsafeValue struct {
	Val   unsafe.Pointer
	model *model.Model
}

func (u *UnsafeValue) SetColumns(rows *sql.Rows, quote string) error {
	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	if len(cols) != len(u.model.ColToFieldMap) {
		return errors2.ErrCountColumns
	}

	valPtrList := make([]interface{}, 0, len(cols))
	for _, colName := range cols {
		colName = strings.ReplaceAll(colName, quote, "")
		field := u.model.FieldToColMap[colName]
		addr := unsafe.Pointer(uintptr(u.Val) + field.Offset)
		val := reflect.NewAt(field.Typ, addr)
		valPtrList = append(valPtrList, val.Interface())
	}

	return rows.Scan(valPtrList...)
}

func (u *UnsafeValue) Field(colName string) (any, error) {
	fd, ok := u.model.ColToFieldMap[colName]
	if !ok {
		return nil, errors2.ErrNotFoundColumn(colName)
	}
	addr := unsafe.Pointer(uintptr(u.Val) + fd.Offset)
	val := reflect.NewAt(fd.Typ, addr)
	return val.Elem().Interface(), nil
}

func NewUnsafeValue(val any, model *model.Model) (Value, error) {
	return &UnsafeValue{
		Val:   reflect.ValueOf(val).UnsafePointer(),
		model: model,
	}, nil
}

var _ Value = (*UnsafeValue)(nil)
var _ Creator = NewUnsafeValue
